﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using log4net;

namespace Chowpoo.Sql
{
    /// <summary>
    /// 提供基于Linq通用访问数据库功能
    /// Model需继承IDetach
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class LinqAccessor<T> : IDisposable
        where T : class,IDetach, new()
    {

        protected static readonly ILog Log = LogManager.GetLogger(typeof(LinqAccessor<T>));
        private bool _isDisposed;

        private string _mConnectionStringName;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="mConnectionStringName"></param>
        public LinqAccessor(string mConnectionStringName)
        {
            ConnectionStringName = mConnectionStringName;
        }

        /// <summary>
        /// 数据库连接字符串
        /// </summary>
        protected string ConnectionStringName
        {
            get { return _mConnectionStringName; }
            set { _mConnectionStringName = value; }
        }

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public virtual void Dispose(bool disposing)
        {
            if (!this._isDisposed)
            {
                if (disposing)
                {
                    //释放非托管资源
                }

                //释放托管资源
                _mConnectionStringName = null;
                _isDisposed = true;
            }
        }

        #endregion

        /// <summary>
        /// 单个Select
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="deferredLoadingEnabled"></param>
        /// <returns></returns>
        public T SelectSingle(Expression<Func<T, bool>> expression, bool deferredLoadingEnabled = true)
        {
            DataContext<T> dt = DataContext<T>.CreateContext(ConnectionStringName);
            dt.DeferredLoadingEnabled = deferredLoadingEnabled;
            return dt.SourceTable.FirstOrDefault(expression);
        }

        /// <summary>
        /// Select
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public List<T> Select(Expression<Func<T, bool>> expression)
        {
            DataContext<T> dt = DataContext<T>.CreateContext(ConnectionStringName);
            return dt.SourceTable.Where(expression).ToList();
        }

        /// <summary>
        /// SelectQueryable
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public IQueryable<T> SelectQueryable(Expression<Func<T, bool>> expression)
        {
            DataContext<T> dt = DataContext<T>.CreateContext(ConnectionStringName);
            return dt.SourceTable.Where(expression);
        }

        /// <summary>
        /// 分页Select
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="pageNow"></param>
        /// <param name="pageSize"></param>
        /// <param name="itemCount"></param>
        /// <returns></returns>
        public List<T> Select(Expression<Func<T, bool>> expression, int pageNow, int pageSize, out int itemCount)
        {
            var dc = DataContext<T>.CreateContext(ConnectionStringName);
            itemCount = dc.SourceTable.Count();
            return dc.SourceTable.Where(expression).Skip(pageNow * pageSize).Take(pageSize).ToList();
        }

        /// <summary>
        /// 单个添加
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public ChangeSet Add(T info)
        {
            try
            {
                DataContext<T> dt = DataContext<T>.CreateContext(ConnectionStringName);
                dt.SourceTable.InsertOnSubmit(info);
                ChangeSet result = dt.GetChangeSet();
                dt.SubmitChanges();
                return result;
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("类型{0}数据库执行插入出错！", typeof(T).FullName), ex);
                return null;
            }
        }

        /// <summary>
        /// 批量添加
        /// </summary>
        /// <param name="infos"></param>
        /// <returns></returns>
        public ChangeSet Add(IEnumerable<T> infos)
        {
            try
            {
                DataContext<T> dt = DataContext<T>.CreateContext(ConnectionStringName);
                dt.SourceTable.InsertAllOnSubmit(infos);
                ChangeSet result = dt.GetChangeSet();
                dt.SubmitChanges();
                return result;
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("类型{0}数据库执行批量插入出错！", typeof(T).FullName), ex);
                return null;
            }
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public ChangeSet Update(T info)
        {
            try
            {
                DataContext<T> dt = DataContext<T>.CreateContext(ConnectionStringName);
                info.Detach();
                dt.SourceTable.Attach(info, true);
                ChangeSet result = dt.GetChangeSet();
                dt.SubmitChanges();
                return result;
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("类型{0}数据库执行更新出错！", typeof(T).FullName), ex);
                return null;
            }
        }

        public ChangeSet Update(IEnumerable<T> infos)
        {
            try
            {
                DataContext<T> dt = DataContext<T>.CreateContext(ConnectionStringName);
                var list = infos.ToList();
                foreach (var item in list)
                {
                    item.Detach();
                }
                dt.SourceTable.AttachAll(list, true);
                ChangeSet result = dt.GetChangeSet();
                dt.SubmitChanges();
                return result;
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("类型{0}数据库执行批量插入出错！", typeof(T).FullName), ex);
                return null;
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public ChangeSet Delete(T info)
        {
            try
            {
                DataContext<T> dt = DataContext<T>.CreateContext(ConnectionStringName);
                info.Detach();
                dt.SourceTable.Attach(info, true);
                dt.SourceTable.DeleteOnSubmit(info);
                ChangeSet result = dt.GetChangeSet();
                dt.SubmitChanges();
                return result;
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("类型{0}数据库执行删除出错！", typeof(T).FullName), ex);
                return null;
            }
        }

        public ChangeSet Delete(IEnumerable<T> list)
        {
            try
            {
                DataContext<T> dt = DataContext<T>.CreateContext(ConnectionStringName);
                var toDelete = list.ToList();
                foreach (var item in toDelete)
                {
                    item.Detach();
                }
                dt.SourceTable.AttachAll(toDelete);
                dt.SourceTable.DeleteAllOnSubmit(toDelete);
                ChangeSet result = dt.GetChangeSet();
                dt.SubmitChanges();
                return result;
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("类型{0}数据库执行批量删除数据库出错！", typeof(T).FullName), ex);
                return null;
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public ChangeSet Delete(Expression<Func<T, bool>> expression)
        {
            try
            {
                var toDelete = Select(expression);
                return Delete(toDelete);
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("类型{0}数据库执行条件删除数据库出错！", typeof(T).FullName), ex);
                return null;
            }
        }

    }
}
